import React, { Component } from 'react';
import { Animated, Dimensions, ScrollView, View } from 'react-native';
import { map, min } from 'lodash';
import PropTypes from 'prop-types';
import Carousel from 'react-native-snap-carousel';
import DefaultHeader from './DefaultHeader';
import { SegmentedBar } from 'teaset';

const headerCollapsedHeight = 46;
const { width } = Dimensions.get('screen');

const styles = {
  tabsContainer: {
    position: 'absolute',
    bottom: 0,
    left: 0,
    right: 0,
    alignItems: 'stretch',
  },
};

class CollapsibleTabs extends Component {

  scrolls = [];
  contentHeights = [];
  layoutMeasurements = [];

  constructor(props) {
    super(props);
    this.headerExpandedHeight = props.customTabBarHeight || headerCollapsedHeight;
    this.footerHeight = 0;
    this.state = {
      scrollY: new Animated.Value(0),
      selectedTab: 0,
      triggerCollapseTabs: [],
      screenWidth: width
    };
  }

  componentDidMount() {

  }

  changeToTab(index) {
    this.carousel && this.carousel.snapToItem(index);
  }

  onChangePage(index) {
    console.log('onChangePage');
    let should = true;
    if (this.props.shouldChangeTab) {
      should = this.props.shouldChangeTab(index);
    }
    if (should) {
      const { scrollY } = this.state;
      Animated.timing(scrollY, {
        toValue: min([this.scrolls[index] || 0, this.headerExpandedHeight]),
        duration: 200,
        useNativeDriver: true,
      }).start();

      this.carousel.snapToItem(index);
      this.setState({ selectedTab: index });
      if (this.props.onTabChanged) {
        this.props.onTabChanged(index);
      }
    }
    else {
      if (this.segment) {
        this.segment.activeIndex = this.state.selectedTab;
      }
    }
  }

  changeTabView(index) {
    this.onChangePage(index);
    this.setState({ selectedTab: index }, () => this.segment && this.segment.forceUpdate());
  }

  resetTriggerCollapseTabs(index) {
    this.state.triggerCollapseTabs[index] = false;
    this.forceUpdate();
  }

  setTriggerCollapseTabs(index) {
    this.state.triggerCollapseTabs[index] = true;
    this.forceUpdate();
  }


  render() {
    const { selectedTab, scrollY } = this.state;
    const { collapsibleContent, tabs } = this.props;
    const { headerExpandedHeight } = this;
    const height = headerExpandedHeight - this.props.customTabBarHeight || headerCollapsedHeight;
    let headerHeight = scrollY.interpolate({
      inputRange: [0, height],
      outputRange: [0, -(height)],
      extrapolate: 'clamp',
    });
    if (this.props.tabs[selectedTab].inverted) {
      if (this.state.triggerCollapseTabs[selectedTab]) {
        if ((this.contentHeights[selectedTab] - this.scrolls[selectedTab]) <= this.layoutMeasurements[selectedTab]) {
          headerHeight = scrollY.interpolate({
            inputRange: [this.contentHeights[selectedTab] - this.layoutMeasurements[selectedTab] - height, this.contentHeights[selectedTab] - this.layoutMeasurements[selectedTab]],
            outputRange: [-(height), 0],
            extrapolate: 'clamp',
          });
        }
        else {
          headerHeight = new Animated.Value(-(height));
        }
      }
      else {
        headerHeight = new Animated.Value(0);
      }
    }

    this.headerHeight = headerHeight;

    const scrollProps = (index, inverted, style, onScroll) => ({
      contentContainerStyle: inverted ? { ...style, paddingBottom: headerExpandedHeight, paddingTop: this.footerHeight } : { ...style, paddingTop: headerExpandedHeight, paddingBottom: this.footerHeight },
      scrollEventThrottle: 16,
      onScroll: Animated.event([{
        nativeEvent: {
          contentOffset: {
            y: this.state.scrollY,
          },
        },
      }], {
        listener: ({ nativeEvent }) => {
          const y = nativeEvent.contentOffset.y;
          this.scrolls[index] = y;
          const oldHeight = this.contentHeights[index];
          this.contentHeights[index] = nativeEvent.contentSize.height;
          this.layoutMeasurements[index] = nativeEvent.layoutMeasurement.height;
          onScroll && onScroll(nativeEvent.contentOffset);
          if (inverted) {
            if (this.state.triggerCollapseTabs[index] && (this.contentHeights[index] - y) <= this.layoutMeasurements[index] ){
              this.forceUpdate();
            }
            else if (!this.state.triggerCollapseTabs[index] && y >= height) {
              this.state.triggerCollapseTabs[index] = true;
              this.forceUpdate();
            }
            if (oldHeight !== this.contentHeights[index]){
              this.forceUpdate();
            }
          }
        },
        useNativeDriver: false
      }),
    });

    return (
        <View style={{ flex: 1, width: '100%' }}>
          <Carousel
              ref={ref => this.carousel = ref}
              onSnapToItem={index => this.changeTabView(index)}
              style={{ flex: 1, width: '100%' }}
              data={tabs}
              scrollEnabled={this.props.scrollEnabled}
              itemWidth={this.props.style.width || this.state.screenWidth}
              sliderWidth={this.props.style.width || this.state.screenWidth}
              inactiveSlideScale={1}
              renderItem={({ item: { component, isFlatList, inverted }, index }) => (
                  isFlatList
                      ? React.cloneElement(component, scrollProps(index, inverted, component.props.contentContainerStyle, component.props.onScroll))
                      : (
                          <ScrollView {...scrollProps(index, inverted)}>
                            {component}
                          </ScrollView>
                      )
              )}
          />
          {/* HEADER */}
          <Animated.View
              style={{
                transform: [{ translateY: headerHeight }],
                position: 'absolute',
                left: 0,
                right: 0,
                top: 0,
              }}
              onLayout={({ nativeEvent }) => {
                if (this.headerExpandedHeight === this.props.customTabBarHeight || headerCollapsedHeight) {
                  this.forceUpdate();
                }
                this.headerExpandedHeight = nativeEvent.layout.height + 0.1;
              }}
          >
            {collapsibleContent}
            <View style={{ height: this.props.customTabBarHeight || headerCollapsedHeight }} />
            <View style={styles.tabsContainer}>
              {this.props.customTabBar ? React.cloneElement(this.props.customTabBar, {
                onChange: index => this.onChangePage(index),
                activeIndex: selectedTab,
              }) : <SegmentedBar
                  justifyItem={'fixed'}
                  indicatorType={'itemWidth'}
                  indicatorPosition={'bottom'}
                  indicatorLineColor={this.props.tabBarTintColor || '#FF4857'}
                  indicatorLineWidth={3}
                  indicatorPositionPadding={0}
                  animated={true}
                  onChange={index => this.onChangePage(index)}
                  activeIndex={selectedTab}
                  ref={v => this.segment = v}
                  style={{...this.props.tabBarStyle, height: this.props.customTabBarHeight || headerCollapsedHeight}}
              >
                {
                  map(tabs, ({ label }) => {
                    return <SegmentedBar.Item key={label} title={label}
                                              activeTitleStyle={{ color: this.props.tabBarTintColor || '#FF4857', fontSize: 15 }}
                                              titleStyle={{ fontSize: 15, color: this.props.titleColor || '#666' }}
                    />;
                  })
                }
              </SegmentedBar>}
            </View>
          </Animated.View>
          <View style={{
            position: 'absolute',
            left: 0,
            right: 0,
            bottom: 0,
          }}
                onLayout={({ nativeEvent }) => {
                  this.footerHeight = nativeEvent.layout.height + 0.1;
                  this.forceUpdate();
                }}
          >
            {this.props.renderTabFooter && this.props.renderTabFooter(this.state.selectedTab)}
          </View>
        </View>
    );
  }
}

CollapsibleTabs.defaultProps = {
  collapsibleContent: (<DefaultHeader />),
  customTabBarHeight: 44,
  scrollEnabled: true,
  style: { width: width }
};

CollapsibleTabs.propTypes = {
  collapsibleContent: PropTypes.element,
  renderTabFooter: PropTypes.func,
  tabs: PropTypes.arrayOf(
      PropTypes.shape({
        label: PropTypes.string,
        component: PropTypes.element,
        isFlatList: PropTypes.bool,
        inverted: PropTypes.bool
      }),
  ).isRequired,
  onTabChanged: PropTypes.func,
  items: PropTypes.any,
  onChange: PropTypes.any,
  customTabBar: PropTypes.element,
  customTabBarHeight: PropTypes.number,
  onOffsetChange: PropTypes.func,
  scrollEnabled: PropTypes.bool,
  tabBarStyle: PropTypes.object,
  tabBarTintColor: PropTypes.string,
  shouldChangeTab: PropTypes.func
};

export default CollapsibleTabs;
